package javax.xml.parsers;

import javax.xml.validation.Schema;
import org.apache.harmony.xml.parsers.SAXParserFactoryImpl;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;

/**
 * SAX 解析器工厂：能够配置和获取基于SAX的解析器来解析XML文档。
 */
public abstract class SAXParserFactory {

    /**
     * 解析器是否需要验证
     */
    private boolean validating = false;

    /**
     * 解析器名称空间是否已经知道</p>
     */
    private boolean namespaceAware = false;

    /**
     * 受保护的构造函数强制使用{@link #newInstance()}.
     */
    protected SAXParserFactory () {

    }

    /**
     * 返回SAXParserFactory实例
     *
     * 与其他Java实现不同，此方法不涉及系统属性、属性文件或服务API。
     *
     * @return a new SAXParserFactory.
     * @exception FactoryConfigurationError never. 包括与其他Java实现的API兼容性。
     */
    public static SAXParserFactory newInstance() {
        // 直接实例化类而不是使用反射
        return new SAXParserFactoryImpl();
    }

    /**
     * 返回指定工厂名称的实例 {@code SAXParserFactory}.
     *就是根据字符串（例如"javax.xml.parsers.SAXParserFactory"）获取SAXParserFactory
     * @throws FactoryConfigurationError 如果 {@code factoryClassName} 不可用或不能被实例化。
     * @since 1.6
     */
    public static SAXParserFactory newInstance(String factoryClassName, ClassLoader classLoader) {
        if (factoryClassName == null) {
            throw new FactoryConfigurationError("factoryClassName == null");
        }
        if (classLoader == null) {
            classLoader = Thread.currentThread().getContextClassLoader();
        }
        try {
            Class<?> type = classLoader != null
                    ? classLoader.loadClass(factoryClassName)
                    : Class.forName(factoryClassName);
            return (SAXParserFactory) type.newInstance();
        } catch (ClassNotFoundException e) {
            throw new FactoryConfigurationError(e);
        } catch (InstantiationException e) {
            throw new FactoryConfigurationError(e);
        } catch (IllegalAccessException e) {
            throw new FactoryConfigurationError(e);
        }
    }

    /**
     * 使用当前配置的工厂参数创建SAXParser的新实例
     *
     * @return A new instance of a SAXParser.
     * @exception ParserConfigurationException 如果无法创建满足请求的配置的解析器。
     * @exception SAXException for SAX errors.
     */

    public abstract SAXParser newSAXParser() throws ParserConfigurationException, SAXException;


    /**
     * 指定解析器是否提供XML名称空间的支持。 默认情况下，这个值被设置为false.
     * @param awareness 解析器将提供对XML名称空间的支持，则为true; 否则为false。
     */

    public void setNamespaceAware(boolean awareness) {
        this.namespaceAware = awareness;
    }

    /**
     * 指定解析器是否在分析文档时对其进行验证。 默认情况下为false.
     *
     * 请注意，这里的“验证”是指XML建议中定义的<a href="http://www.w3.org/TR/REC-xml#proc-types">验证解析器</a>
     * 	换句话说,它基本上只是控制DTD验证。
     * 	（除了在JAXP 1.2中定义的传统两个属性外，请参阅此处了解更多详细信息。）
     *
     * 要使用现代模式语言（如W3C XML模式或RELAX NG代替DTD），
     * 可以通过将{@link #setValidating(boolean)}方法保留为false来将分析器配置为非验证分析器。
     * 然后使用{@link #setSchema(Schema)} 方法将模式关联到解析器。
     *
     * @param validating ：如果解析器在解析文档时验证文档，则为true; 否则为false。
     */

    public void setValidating(boolean validating) {
        this.validating = validating;
    }

    /**
     * 指示工厂是否配置为生成可识别名称空间的解析器。
     * @return 如果工厂被配置为生成可识别名称空间的解析器，则为true; 否则为false
     */

    public boolean isNamespaceAware() {
        return namespaceAware;
    }

    /**
     * 指示是否将工厂配置为生成在解析期间验证XML内容的解析器。
     * @return 如果工厂被配置为生成在解析期间生成验证XML内容的解析器，则为true; 否则为false
     */

    public boolean isValidating() {
        return validating;
    }

    /**
     *
     * 核心功能和属性的清单可以在这里找到:http://www.saxproject.org。
     * 所有的实现都需要支持{@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING}特性。
     * 这些属性都会被底层XMLReader来识别使用。
     *
     * @param name 要设置的功能的名称
     * @param value 要设置的功能的值。
     *
     * @exception ParserConfigurationException 如果无法创建满足请求的配置的解析器。
     * @exception SAXNotRecognizedException 底层XMLReader不能识别属性名称时。
     * @exception SAXNotSupportedException 当底层XMLReader识别属性名称但不支持该属性时。
     * @throws NullPointerException If the <code>name</code> parameter is null.
     *
     * @see org.xml.sax.XMLReader#setFeature
     */
    public abstract void setFeature(String name, boolean value)
        throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException;

    /**
     * @param name 要检索的属性的名称。
     * @return Value of the requested property.
     * @exception ParserConfigurationException 如果无法创建满足请求的配置的解析器。
     * @exception SAXNotRecognizedException 层XMLReader不能识别属性名称时。
     * @exception SAXNotSupportedException 当底层XMLReader识别属性名称但不支持该属性时。
     *
     * @see org.xml.sax.XMLReader#getProperty
     */
    public abstract boolean getFeature(String name)
        throws ParserConfigurationException, SAXNotRecognizedException,
                SAXNotSupportedException;

    /**
     * Gets the {@link Schema} object specified through the {@link #setSchema(Schema schema)} method.
     *获取通过{@link #setSchema(Schema schema)}方法指定的{@link Schema}对象。
     *
     * @throws UnsupportedOperationException 为了向后兼容，在使用早期版本的JAXP的实现时，将引发此异常。
     * @return 最后通过{@link #setSchema(Schema)}方法设置的{@link Schema}对象;如果自从创建{@link SAXParserFactory} 之后未调用该方法，则为null。
     *
     * @since 1.5
     */
    public Schema getSchema() {
        throw new UnsupportedOperationException(
            "This parser does not support specification \""
            + this.getClass().getPackage().getSpecificationTitle()
            + "\" version \""
            + this.getClass().getPackage().getSpecificationVersion()
            + "\""
            );
    }

    /**
     * 设置由该工厂创建的解析器使用的{@link Schema}。
     *
     * 当{@link Schema}非空时，解析器将使用从其创建的验证器来验证文档，然后将信息传递给应用程序。
     *
     * 当验证器发现警告/错误/致命错误时，解析器必须处理它们，就好像这些错误是由解析器本身发现的一样。
     * 句话说，如果用户指定{@link org.xml.sax.ErrorHandler} 被设置，它必须接收这些错误，如果没有，他们必须根据实现特定的默认错误处理规则来处理。
     *
     * 验证器可以修改SAX事件流（例如，通过添加文档中缺少的缺省值），解析器负责确保应用程序将接收这些修改后的事件流。
     *
     * 最初，{@link Schema}被设置为null。
     *
     * 即使{@link #isValidating()}方法返回false，该处理也会生效
     *
     * 将http://java.sun.com/xml/jaxp/properties/schemaSource属性和/或http://java.sun.com/xml/jaxp/properties/schemaLanguage属性与非 -null {@link Schema}对象。
     * 这些配置将在{@link SAXParser}上设置这些属性时导致{@link SAXException}异常。
     *
     * <h4>实现者注意：/h4>
     *
     * 解析器必须能够使用任何{@link Schema}实现。
     * 然而，只要分析器和模式产生规范中描述的结果，就可以使用实现特定的自定义机制。
     *
     * @param schema 使用模式，空删除模式。
     * @throws UnsupportedOperationException 为了向后兼容，在使用早期版本的JAXP的实现时，将引发此异常。
     *
     * @since 1.5
     */
    public void setSchema(Schema schema) {
        throw new UnsupportedOperationException(
            "This parser does not support specification \""
            + this.getClass().getPackage().getSpecificationTitle()
            + "\" version \""
            + this.getClass().getPackage().getSpecificationVersion()
            + "\""
            );
    }

    /**
     * 设置XInclude处理的状态。
     *
     * 如果按照<a href="http://www.w3.org/TR/xinclude/"> XML包含（XInclude）V1.0 </a>中的规定处理，则在文档实例中找到XInclude标记。
     *
     * XInclude处理默认为false。
     *
     * @param state 将XInclude处理设置为true或false
     *
     * @throws UnsupportedOperationException 为了向后兼容，在使用早期版本的JAXP的实现时，将引发此异常。
     * @since 1.5
     */
    public void setXIncludeAware(final boolean state) {
        throw new UnsupportedOperationException(
            "This parser does not support specification \""
            + this.getClass().getPackage().getSpecificationTitle()
            + "\" version \""
            + this.getClass().getPackage().getSpecificationVersion()
            + "\""
            );
    }

    /**
     * 获取XInclude处理的状态。
     *
     * @return XInclude处理的当前状态
     * @throws UnsupportedOperationException 为了向后兼容，在使用早期版本的JAXP的实现时，将引发此异常
     * @since 1.5
     */
    public boolean isXIncludeAware() {
        throw new UnsupportedOperationException(
            "This parser does not support specification \""
            + this.getClass().getPackage().getSpecificationTitle()
            + "\" version \""
            + this.getClass().getPackage().getSpecificationVersion()
            + "\""
            );
    }
}

